#include<map>
#include<functional>
#include<ctype.h>
#include<tuple>
#include<string.h>
#include"log.h"
#include"util.h"
#include"config.h"
#include"mutex.h"



namespace qtch{

static Logger::ptr logger = QTCH_LOG_NAME("system");

const char * LogLevel::ToString(LogLevel::Level level){
    switch(level){
#define XX(name) \
    case LogLevel::name: \
        return #name; \
        break;

    XX(UNKNOW);
    XX(DEBUG);
    XX(INFO);
    XX(WARN);
    XX(ERROR);
    XX(FATAL);
#undef XX
    }
    return "UNKNOW";
}

LogLevel::Level LogLevel::FromString(const std::string& str){
#define XX(level,v) \
    if(str == #v) { \
        return LogLevel::level; \
    }

    XX(DEBUG,debug);
    XX(INFO,info);
    XX(WARN,warn);
    XX(ERROR,error);
    XX(FATAL,fatal);

    XX(DEBUG,DEBUG);
    XX(INFO,INFO);
    XX(WARN,WARN);
    XX(ERROR,ERROR);
    XX(FATAL,FATAL);
#undef XX
    return LogLevel::DEBUG;
}

LogEvent::LogEvent(Logger::ptr logger , LogLevel::Level level, 
            const char * fileName, int32_t line, uint32_t elapse, 
            uint32_t threadId, uint32_t fiberId,
            uint64_t time, const std::string& threadName)
    :m_logger(logger)
    ,m_level(level)
    ,m_file(fileName)
    ,m_line(line)
    ,m_elapse(elapse)
    ,m_threadId(threadId)
    ,m_fiberId(fiberId)
    ,m_time(time)
    ,m_threadName(threadName){
}

LogEventWrap::LogEventWrap(LogEvent::ptr p){
    m_event = p;
}
LogEventWrap::~LogEventWrap(){
    m_event->getLogger()->log(m_event->getLevel(),m_event);
}
std::stringstream& LogEventWrap::getSS(){
    return m_event->getSS();
}



class MessageFormatItem : public LogFormatter::FormatterItem{
public:
    MessageFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getContent();
    }
};

class LevelFormatItem : public LogFormatter::FormatterItem{
public:
    LevelFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<LogLevel::ToString(event->getLevel());
    }
};

class ElapseFormatItem : public LogFormatter::FormatterItem{
public:
    ElapseFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getElapse();
    }
};

class NameFormatItem : public LogFormatter::FormatterItem{
public:
    NameFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getLogger()->getName();
    }
};

class ThreadIdFormatItem : public LogFormatter::FormatterItem{
public:
    ThreadIdFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getThreadId();
    }
};

class NewLineFormatItem : public LogFormatter::FormatterItem{
public:
    NewLineFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<std::endl;
    }
};

class DateTimeFormatItem : public LogFormatter::FormatterItem{
public:
    DateTimeFormatItem(const std::string& format = "%Y-%m-%d %H:%M:%S")
        :m_formate(format){
            if(m_formate.empty()){
                m_formate = "%Y-%m-%d %H:%M:%S";
            }
        }
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        struct tm tm;
        time_t time = event->getTime();
        localtime_r(&time, &tm);
        char buf[64];
        strftime(buf, sizeof(buf), m_formate.c_str(), &tm);
        os << buf;
    }

private:
    std::string m_formate;
};

class FilenameFormatItem : public LogFormatter::FormatterItem{
public:
    FilenameFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getFileName();
    }
};

class LineFormatItem : public LogFormatter::FormatterItem{
public:
    LineFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getLine();
    }
};

class TabFormatItem : public LogFormatter::FormatterItem{
public:
    TabFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<"\t";
    }
};

class FiberIdFormatItem : public LogFormatter::FormatterItem{
public:
    FiberIdFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getFiberId();
    }
};

class ThreadNameFormatItem : public LogFormatter::FormatterItem{
public:
    ThreadNameFormatItem(const std::string& str = "") {}
    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<event->getThreadName();
    }
};

class StringFormatItem : public LogFormatter::FormatterItem{
public:
    StringFormatItem(const std::string& str = "") :m_string(str){}

    void format(std::ostream& os,Logger::ptr logger,LogEvent::ptr event){
        os<<m_string;
    }
private:
    std::string m_string;
};

LogFormatter::LogFormatter(const std::string& pattern)
    :m_pattern(pattern){
        init();
}

void LogFormatter::init(){
    std::vector<std::tuple<std::string, std::string, int> >vec;
    static std::map<std::string, std::function<FormatterItem::ptr(const std::string& str)> >s_format_items = {
#define XX(str,C) \
    {#str,[](const std::string & fmt){return FormatterItem::ptr(new C(fmt));}}
    XX(m,MessageFormatItem),            //m:消息
    XX(p,LevelFormatItem),              //p:日志级别
    XX(r,ElapseFormatItem),             //r:累计毫秒数
    XX(c,NameFormatItem),               //c:日志名称
    XX(t,ThreadIdFormatItem),           //t:线程id
    XX(n,NewLineFormatItem),            //n:换行
    XX(d,DateTimeFormatItem),           //d:时间
    XX(f,FilenameFormatItem),           //f:文件名
    XX(l,LineFormatItem),               //l:行号
    XX(T,TabFormatItem),                //T:Tab
    XX(F,FiberIdFormatItem),            //F:协程id
    XX(N,ThreadNameFormatItem),          //N:线程名称
#undef XX
    };
    std::string temp_str;
    for(size_t i = 0; i < m_pattern.size(); ++i){
        if(m_pattern[i] != '%'){
            temp_str.append(1, m_pattern[i]);
            continue;
        }
        if(i+1 < m_pattern.size()){
            if(m_pattern[i + 1] == '%'){
                temp_str.append(1,'%');
                i++;
                continue;
            }
        }
        size_t n = i + 1;
        std::string str;
        std::string fmt;
        int fmt_status = 0;
        while(n<m_pattern.size()){
            if(fmt_status==0){
                if(isalpha(m_pattern[n])){
                    str.append(1,m_pattern[n]);
                }
                else if(m_pattern[n]=='{'){
                    fmt_status=1;
                }
                else {
                    break;
                }
            }
            else if(fmt_status==1){
                if(m_pattern[n] != '}'){
                    fmt.append(1,m_pattern[n]);
                }
                else{
                    fmt_status = 2;
                    break;
                }
            }
            ++n;
        }
        if(fmt_status == 0 || fmt_status == 2){
            if(!temp_str.empty()){
                vec.push_back(std::make_tuple(temp_str,std::string(),0));
                temp_str.clear();
            }
            vec.push_back(std::make_tuple(str,fmt,1));
            i = n -1;
            if(fmt_status == 2) i++;
        }else if(fmt_status == 1){
            std::cout << "pattern parse error: " << str << "-" << fmt << std::endl;
            m_error = true;
            vec.push_back(std::make_tuple("<<pattern_error>>", fmt, 0));
        }
        
    }
    if(!temp_str.empty()){
        vec.push_back(std::make_tuple(temp_str,std::string(),0));
        temp_str.clear();
    }

    for(auto i : vec){
        if(std::get<2>(i) == 0){
            m_formatItem.push_back(FormatterItem::ptr(new StringFormatItem(std::get<0>(i))));
        }else{
            auto it = s_format_items.find(std::get<0>(i));
            if(it == s_format_items.end()){
                m_formatItem.push_back(FormatterItem::ptr(new StringFormatItem("<<error_format %" + std::get<0>(i) + ">>")));
                m_error = true;
            }else{
                m_formatItem.push_back(it->second(std::get<1>(i)));
            }
        }
    }

}
std::string LogFormatter::format(Logger::ptr logger,LogEvent::ptr event){
    std::stringstream ss;
    format(ss,logger,event);
    return ss.str();
}
std::ostream& LogFormatter::format(std::ostream& ifs,Logger::ptr logger,LogEvent::ptr event){
    for(auto & i:m_formatItem){
        i->format(ifs,logger,event);
    }
    return ifs;
}

LogFormatter::ptr LogAppender::getFomatter(){
    return m_formatter;
}

void LogAppender::setFormatter(LogFormatter::ptr formatter){
    m_formatter = formatter;
    if(m_formatter){
        m_hasFormatter = true;
    }else{
        m_hasFormatter = false;
    }
}

#define STDOUT_COLOR_DEF(XX)\
    XX(DEFAULT,       "\033[0m",            "default");\
    XX(Blue,          "\033[0;34m",         "blue");\
    XX(Green,         "\033[0;32m",         "green");\
    XX(Red,           "\033[0;31m",         "red");\
    XX(Yellow,        "\033[0;33m",         "yellow");\
    XX(White,         "\033[0;37m",         "white");\
    XX(Cyan,          "\033[0;36m",         "cyan");\
    XX(Magenta,       "\033[0;35m",         "magenta");\
    XX(BrightBlue,    "\033[1;34m",         "brightBlue");\
    XX(BrightGreen,   "\033[1;32m",         "brightGreen");\
    XX(BrightRed,     "\033[1;31m",         "brightRed");\
    XX(BrightYellow,  "\033[1;33m",         "brightYellow");\
    XX(BrightWhite,   "\033[1;37m",         "brightWhite");\
    XX(BrightCyan,    "\033[1;36m",         "brightCyan");\
    XX(BrightMagenta, "\033[1;35m",         "brightMagenta");



const std::string StdoutLogColor::getColorString(LogLevel::Level level){
    Color c;
    if(level == LogLevel::Level::DEBUG){
        c = m_color_debug;
    }else if(level == LogLevel::Level::INFO){
        c = m_color_info;
    }else if(level == LogLevel::Level::WARN){
        c = m_color_warn;
    }else if(level == LogLevel::Level::ERROR){
        c = m_color_error;
    }else if(level == LogLevel::Level::FATAL){
        c = m_color_fatal;
    }
#define XX(color,code,name)\
    if(c==Color::color){\
        return name;\
    }

    STDOUT_COLOR_DEF(XX);
#undef XX
    std::cout << "invaild log color=" << c << std::endl;
    return "default";
}

const std::string StdoutLogColor::getColorCode(StdoutLogColor::Color color){
#define XX(c,code,name)\
    if(color==Color::c){\
        return code;\
    }

    STDOUT_COLOR_DEF(XX);
#undef XX
    std::cout << "getColorCode(color) color not define in STDOUT_COLOR_DEF" << std::endl;
    return "default";

}

const std::string StdoutLogColor::getColorCode(LogLevel::Level level){
    Color c;
    if(level == LogLevel::Level::DEBUG){
        c = m_color_debug;
    }else if(level == LogLevel::Level::INFO){
        c = m_color_info;
    }else if(level == LogLevel::Level::WARN){
        c = m_color_warn;
    }else if(level == LogLevel::Level::ERROR){
        c = m_color_error;
    }else if(level == LogLevel::Level::FATAL){
        c = m_color_fatal;
    }
#define XX(color,code,name)\
    if(c==Color::color){\
        return code;\
    }

    STDOUT_COLOR_DEF(XX);
#undef XX
    std::cout << "invaild log color=" << c << std::endl;
    return "default";
}

void StdoutLogColor::setColorFromString(LogLevel::Level level,const std::string& str){
    Color c = Color::DEFAULT;

    bool flag = false;
#define XX(color,code,name)\
    if(str == name){\
        flag = true;\
        c = Color::color;\
    }

    STDOUT_COLOR_DEF(XX);

#undef XX
    if(!flag){
        std::cout << "setColorFromString invaild log color, level=" << level << " str=" << str << std::endl;
    }
    if(level == LogLevel::Level::DEBUG){
        m_color_debug = c;
    }else if(level == LogLevel::Level::INFO){
        m_color_info = c;
    }else if(level == LogLevel::Level::WARN){
        m_color_warn = c;
    }else if(level == LogLevel::Level::ERROR){
        m_color_error = c;
    }else if(level == LogLevel::Level::FATAL){
        m_color_fatal = c;
    }

}


StdoutLogAppender::StdoutLogAppender(StdoutLogColor color){
    m_color = color;
}

void StdoutLogAppender::log(std::shared_ptr<Logger> logger, LogLevel::Level level,LogEvent::ptr event){
    if(level >= getLevel()){
        Mutex::Lock lock(m_mutex);
        std::cout << m_color.getColorCode(level);
        getFomatter()->format(std::cout, logger, event);
        std::cout << m_color.getColorCode(StdoutLogColor::Color::DEFAULT);
        std::cout.flush();
    }
}



FileLogAppender::FileLogAppender(const std::string& fileName)
    :m_originFileName(fileName){
    Mutex::Lock lock(m_mutex);
    init();
    m_fileName = getFileName();
    reopen();
}

void FileLogAppender::log(std::shared_ptr<Logger> logger, LogLevel::Level level,LogEvent::ptr event){
    if(level >= getLevel()){
        Mutex::Lock lock(m_mutex);
        uint64_t now = event->getTime();
        if(now >= (m_lastTime + 30)){
            reopen();
            m_lastTime = now;
        }
        if(!getFomatter()->format(m_fileSteam, logger, event)){
            std::cout<<"log file format error"<<std::endl;
        }
    }
}

bool FileLogAppender::reopen(){
    if(m_fileSteam){
        m_fileSteam.close();
    }
    m_fileName = getFileName();
    if(!FSUtil::isFile(m_fileName)){
        if(FSUtil::isDir(m_fileName)){
            std::cout << "log file can't be a dir" <<std::endl;
            return false;
        }
        char * dirpath = strdup(m_fileName.c_str());
        char * chr = strrchr(dirpath,'/');
        *chr = '\0';
        FSUtil::MkDir(dirpath);
        free(dirpath);
    }
    m_fileSteam.open(m_fileName.c_str(),std::ios::app);
    return m_fileSteam.is_open();
}

std::string FileLogAppender::getFileName(){
    std::stringstream ss;
    for(size_t i = 0; i < m_formatItem.size(); ++i){
        m_formatItem[i]->format(ss);
    }
    return ss.str();
}

class LogFileNameStringFormatterItem : public FileLogAppender::LogFileNameFormatterItem{
public:
    LogFileNameStringFormatterItem(const std::string& str = "") :m_string(str){}
    void format(std::ostream& os){
        os<<m_string;
    }
private:
    std::string m_string;
};

class LogFileNameDataFormatterItem : public FileLogAppender::LogFileNameFormatterItem{
public:
    LogFileNameDataFormatterItem(const std::string& format = "%Y-%m-%d")
        :m_formate(format){
            if(m_formate.empty()){
                m_formate = "%Y-%m-%d";
            }
        }
    void format(std::ostream& os){
        struct tm tm;
        time_t now_time = time(0);
        localtime_r(&now_time, &tm);
        char buf[64];
        strftime(buf, sizeof(buf), m_formate.c_str(), &tm);
        os << buf;
    }

private:
    std::string m_formate;

};

void FileLogAppender::init(){
    static std::map<std::string, std::function<LogFileNameFormatterItem::ptr(const std::string& str)> > s_format_items = {
#define XX(str, C)\
    {#str, [](const std::string & fmt){return LogFileNameFormatterItem::ptr(new C(fmt));}}
        XX(d, LogFileNameDataFormatterItem),

#undef XX
    };
    std::vector<std::tuple<std::string, std::string, int> >vec;
    std::string temp_str;
    for(size_t i = 0; i < m_originFileName.size(); ++i){
        if(m_originFileName[i] != '%'){
            temp_str.append(1, m_originFileName[i]);
            continue;
        }
        if(i+1 < m_originFileName.size()){
            if(m_originFileName[i + 1] == '%'){
                temp_str.append(1,'%');
                i++;
                continue;
            }
        }
        size_t n = i + 1;
        std::string str;
        std::string fmt;
        int fmt_status = 0;
        while(n<m_originFileName.size()){
            if(fmt_status==0){
                if(isalpha(m_originFileName[n])){
                    str.append(1,m_originFileName[n]);
                }
                else if(m_originFileName[n]=='{'){
                    fmt_status=1;
                }
                else {
                    break;
                }
            }
            else if(fmt_status==1){
                if(m_originFileName[n] != '}'){
                    fmt.append(1,m_originFileName[n]);
                }
                else{
                    fmt_status = 2;
                    break;
                }
            }
            ++n;
        }
        if(fmt_status == 0 || fmt_status == 2){
            if(!temp_str.empty()){
                vec.push_back(std::make_tuple(temp_str,std::string(),0));
                temp_str.clear();
            }
            vec.push_back(std::make_tuple(str,fmt,1));
            i = n -1;
            if(fmt_status == 2) i++;
        }else if(fmt_status == 1){
            std::cout << "pattern parse error: " << str << "-" << fmt << std::endl;
            vec.push_back(std::make_tuple("<<pattern_error>>", fmt, 0));
        }
        
    }
    if(!temp_str.empty()){
        vec.push_back(std::make_tuple(temp_str,std::string(),0));
        temp_str.clear();
    }

    for(auto i : vec){
        if(std::get<2>(i) == 0){
            m_formatItem.push_back(LogFileNameFormatterItem::ptr(new LogFileNameStringFormatterItem(std::get<0>(i))));
        }else{
            auto it = s_format_items.find(std::get<0>(i));
            if(it == s_format_items.end()){
                m_formatItem.push_back(LogFileNameFormatterItem::ptr(new LogFileNameStringFormatterItem("<<error_format %" + std::get<0>(i) + ">>")));
            }else{
                m_formatItem.push_back(it->second(std::get<1>(i)));
            }
        }
    }

}

Logger::Logger(const std::string& name)
    :m_name(name)
    ,m_level(LogLevel::INFO){
    m_formatter.reset(new LogFormatter("%d{%Y-%m-%d %H:%M:%S}%T[%p]%T%t%T%N%T%F%T%c%T%r%T%f:%l%T%m%n"));
}

void Logger::setFormatter(LogFormatter::ptr formatter){
    WritescopedLockImp<MutexType> lock(m_mutex);
    m_formatter=formatter;
    for(auto& it : m_appender){
        if(!it->hasFormatter()){
            it->setFormatter(formatter);
        }
    }
}
void Logger::addAppender(LogAppender::ptr appender){
    WritescopedLockImp<MutexType> lock(m_mutex);
    if(!appender->getFomatter()){
        appender->setFormatter(m_formatter);
    }
    m_appender.push_back(appender);
}
void Logger::delAppender(LogAppender::ptr appender){
    ReadScopedLockImp<MutexType> rlock(m_mutex);
    for(auto it = m_appender.begin();it!=m_appender.end();++it){
        if(*it==appender){
            rlock.unlock();
            WritescopedLockImp<MutexType> wlock(m_mutex);
            m_appender.erase(it);
            break;
        }
    }
}
void Logger::clearAppenders(){
    WritescopedLockImp<MutexType> lock(m_mutex);
    m_appender.clear();
}
void Logger::log(LogLevel::Level level,LogEvent::ptr event){
    if(m_level  <= level){
        auto self = shared_from_this();
        ReadScopedLockImp<MutexType> lock(m_mutex);
        if(!m_appender.empty()){
            for(auto& it : m_appender){
                it->log(self,level,event);
            }
        }else if(m_root){
            m_root->log(level, event);
        }
    }
}
void Logger::debug(LogEvent::ptr event){
    log(LogLevel::DEBUG,event);
}
void Logger::info(LogEvent::ptr event){
    log(LogLevel::INFO,event);
}
void Logger::warn(LogEvent::ptr event){
    log(LogLevel::WARN,event);
}
void Logger::error(LogEvent::ptr event){
    log(LogLevel::ERROR,event);
}
void Logger::fatal(LogEvent::ptr event){
    log(LogLevel::FATAL,event);
}

LoggerManger::LoggerManger(){
    WritescopedLockImp<MutexType> Lock(m_mutex);
    m_root.reset(new Logger("root"));
    StdoutLogColor color;
    m_root->addAppender(LogAppender::ptr(new StdoutLogAppender(color)));
    m_logger[m_root->m_name] = m_root;

    init();
}
void LoggerManger::init(){

}
Logger::ptr LoggerManger::getLogger(const std::string& name){
    {
        ReadScopedLockImp<MutexType> Lock(m_mutex);
        auto it = m_logger.find(name);
        if(it!=m_logger.end()){
            return it->second;
        }
    }
    WritescopedLockImp<MutexType> Lock(m_mutex);
    Logger::ptr logger(new Logger(name));
    logger->m_root = m_root;
    m_logger[name] = logger;
    return logger;
}

class LogAppenderDefine{
public:
    bool operator== (const LogAppenderDefine& def)const{
        return def.m_file==m_file
                && def.m_format ==m_format
                && def.type == type
                && def.m_level == m_level;
    }
    std::string m_format;
    qtch::LogLevel::Level m_level = qtch::LogLevel::DEBUG;
    int type = 0; //stdout:1,file:2
    std::string m_file;
    StdoutLogColor m_color;
};

class LogDefine{
public:
    bool operator == (const LogDefine& def)const{
        return def.m_name == m_name
                && def.m_level == m_level
                && def.m_appenders == m_appenders;
    }

    bool operator < (const LogDefine &def)const{
        return def.m_name < m_name;
    }


    std::string m_name;
    qtch::LogLevel::Level m_level = qtch::LogLevel::DEBUG;
    std::list<LogAppenderDefine> m_appenders;
};



template<>
class LexicalCast<std::string ,qtch::LogDefine >{
public:
    std::string operator()(const LogDefine& v){
        YAML::Emitter out;
        out << YAML::BeginMap;
        out << YAML::Key << "name";
        out << YAML::Value << v.m_name;
        out << YAML::Key << "level";
        out << YAML::Value << LogLevel::ToString(v.m_level);
        if(v.m_appenders.size() > 0){
            out << YAML::Key << "appenders";
            out << YAML::Value;
            out << YAML::BeginSeq;
            for(auto it : v.m_appenders){
                out << YAML::BeginMap;
                out << YAML::Key << "level";
                out << YAML::Value << it.m_level;
                if(!it.m_format.empty()){
                    out << YAML::Key << "format";
                    out << YAML::Value << it.m_format;
                }
                switch(it.type){
                    case 0:
                        out << YAML::Key << "type";
                        out << YAML::Value << "StdoutLogAppender";

                        out << YAML::Key << "color";
                        out << YAML::Value;
                        out << YAML::BeginMap;
                        out << YAML::Key << "debug";
                        out << YAML::Value << it.m_color.getColorString(LogLevel::DEBUG);
                        out << YAML::Key << "info";
                        out << YAML::Value << it.m_color.getColorString(LogLevel::INFO);
                        out << YAML::Key << "wran";
                        out << YAML::Value << it.m_color.getColorString(LogLevel::WARN);
                        out << YAML::Key << "error";
                        out << YAML::Value << it.m_color.getColorString(LogLevel::ERROR);
                        out << YAML::Key << "fatal";
                        out << YAML::Value << it.m_color.getColorString(LogLevel::FATAL);
                        out << YAML::EndMap;
                        break;
                    case 1:
                        out << YAML::Key << "type";
                        out << YAML::Value << "FileLogAppender";
                        out << YAML::Key << "file";
                        out << YAML::Value << it.m_file;
                        break;
                }
                out << YAML::EndMap;
            }
            out << YAML::EndSeq;
        }
        return out.c_str();
    }
};

template<>
class LexicalCast<qtch::LogDefine, std::string >{
public:
    LogDefine operator()(const std::string& v){
        LogDefine def;
        YAML::Node node = YAML::Load(v);
        if(node.IsMap()){

        }
        else{

        }
        if(!node["name"].IsDefined()){
            QTCH_LOG_ERROR(logger) << "log config error : name is null";
            throw std::logic_error("log config error : name is null");
        }
        def.m_name = node["name"].as<std::string>();
        if(node["level"].IsDefined()){
            def.m_level = LogLevel::FromString(node["level"].as<std::string>());
        }
        do{
            if(node["appenders"].IsDefined()){
            if(node["appenders"].IsMap()){
                YAML::Node appender = node["appenders"];
                if(!appender["type"].IsDefined()){
                    break;
                }
                LogAppenderDefine appdef;
                std::string type = appender["type"].as<std::string>();
                if(type == "StdoutLogAppender"){
                    appdef.type = 0;
                }
                else if(type == "FileLogAppender"){
                    appdef.type = 1;
                    if(appender["file"].IsDefined()){
                        appdef.m_file = appender["file"].as<std::string>();
                    }
                    else{
                        break;
                    }
                }
                if(appender["level"].IsDefined()){
                    appdef.m_level = LogLevel::FromString(appender["level"].as<std::string>());
                }
                if(appender["format"].IsDefined()){
                    appdef.m_format = appender["format"].as<std::string>();
                }
                def.m_appenders.push_back(appdef);
            }
            else if(node["appenders"].IsSequence()){
                for(size_t i = 0 ; i < node["appenders"].size(); ++i){
                    YAML::Node appender = node["appenders"][i];
                    if(!appender["type"].IsDefined()){
                        break;
                    }
                    LogAppenderDefine appdef;
                    std::string type = appender["type"].as<std::string>();
                    if(type == "StdoutLogAppender"){
                        appdef.type = 0;
                    }
                    else if(type == "FileLogAppender"){
                        appdef.type = 1;
                        if(appender["file"].IsDefined()){
                            appdef.m_file = appender["file"].as<std::string>();
                        }
                        else{
                            break;
                        }
                    }
                    if(appender["level"].IsDefined()){
                        appdef.m_level = LogLevel::FromString(appender["level"].as<std::string>());
                    }
                    if(appender["format"].IsDefined()){
                        appdef.m_format = appender["format"].as<std::string>();
                    }
                    if(appender["color"].IsDefined()){
                        YAML::Node color = appender["color"];
                        if(color["debug"].IsDefined()){
                            appdef.m_color.setColorFromString(LogLevel::DEBUG,color["debug"].as<std::string>());
                        }
                        if(color["info"].IsDefined()){
                            appdef.m_color.setColorFromString(LogLevel::INFO,color["info"].as<std::string>());
                        }
                        if(color["warn"].IsDefined()){
                            appdef.m_color.setColorFromString(LogLevel::WARN,color["warn"].as<std::string>());
                        }
                        if(color["error"].IsDefined()){
                            appdef.m_color.setColorFromString(LogLevel::ERROR,color["error"].as<std::string>());
                        }
                        if(color["fatal"].IsDefined()){
                            appdef.m_color.setColorFromString(LogLevel::FATAL,color["fatal"].as<std::string>());
                        }
                    }
                    def.m_appenders.push_back(appdef);
                }
            }
        }
        }while(0);
        return def;
       
    }

};

ConfigVar<std::set<qtch::LogDefine> >::ptr logDefine = Config::LookUp("logs",std::set<LogDefine>(),"log config");

class __LogInit{
public:
    __LogInit(){
        logDefine->addListener([](const std::set<qtch::LogDefine> &old_value, const std::set<qtch::LogDefine> &new_value){
            QTCH_LOG_DEBUG(logger) << "logger config change";
            for(auto it : new_value){
                Logger::ptr logger = QTCH_LOG_NAME(it.m_name);
                logger->clearAppenders();
                logger->setLevel(it.m_level);
                for(auto app_it :it.m_appenders){
                    qtch::LogAppender::ptr appender;
                    switch(app_it.type){
                        case 0:
                            appender.reset(new qtch::StdoutLogAppender(app_it.m_color));
                            break;
                        case 1:
                            appender.reset(new qtch::FileLogAppender(app_it.m_file));
                            break;
                        default:
                            break;
                    }
                    if(!app_it.m_format.empty()){
                        appender->setFormatter(LogFormatter::ptr(new LogFormatter(app_it.m_format)));
                    }
                    appender->setLevel(app_it.m_level);
                    logger->addAppender(appender);
                }
            }

        });
    }
    
};

static __LogInit __loginit;





















}